/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.library.controller;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;

import javax.imageio.ImageIO;
import javax.validation.Valid;

import lombok.SneakyThrows;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springblade.common.annotation.ServiceLog;
import org.springblade.common.constant.RedisKeyConstant;
import org.springblade.common.constant.TrainingOperateConstant;
import org.springblade.common.constant.TrainingRoleConstant;
import org.springblade.common.exception.TrainingServiceException;
import org.springblade.common.utils.CommonUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.oss.model.BladeFile;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.FileUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.library.bo.LibraryBo;
import org.springblade.modules.personal.entity.SecrecyLevel;
import org.springblade.modules.resource.builder.oss.OssBuilder;
import org.springblade.modules.resource.enums.AttachType;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.library.entity.MaterialLibraryEntity;
import org.springblade.modules.library.vo.MaterialLibraryVO;
import org.springblade.modules.library.wrapper.MaterialLibraryWrapper;
import org.springblade.modules.library.service.IMaterialLibraryService;
import org.springblade.core.boot.ctrl.BladeController;
import org.springframework.web.multipart.MultipartFile;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.springblade.core.cache.constant.CacheConstant.MENU_CACHE;


/**
 * 素材库 控制器
 * @author
 * @since 2023-03-22
 */
@RestController
@AllArgsConstructor
@RequestMapping("blade-materialLibrary/materialLibrary")
@Api(value = "素材库", tags = "素材库接口")
public class MaterialLibraryController extends BladeController {

	private final IMaterialLibraryService materialLibraryService;
	private final CommonUtil commonUtil;

	/**
	 * 对象存储构建类
	 */
	private final OssBuilder ossBuilder;

	private final BladeRedis bladeRedis;

	@SneakyThrows
	@GetMapping("/pdf-convert")
	@ApiOperation(value = "PDF转换成图片", notes = "传入pdf的资源链接")
	public R convertPdfToImage(String pdfUrl) {
		if (StringUtil.isBlank(pdfUrl) || pdfUrl.lastIndexOf(".pdf")<0)throw new TrainingServiceException("非PDF类型的文件不支持预览");
		Object redisResult = bladeRedis.get(RedisKeyConstant.PDF_CONVERT_IMG+pdfUrl);
		if (ObjectUtil.isNotEmpty(redisResult)) return R.data((List<String>)redisResult);
		InputStream inputStream = null;
		URL url = new URL(pdfUrl);
		URLConnection con = url.openConnection();
		con.setConnectTimeout(3 * 1000);
		inputStream = con.getInputStream();
		List<String> resultList=new ArrayList<>();
		PDDocument document = PDDocument.load(inputStream);
		PDFRenderer pdfRenderer = new PDFRenderer(document);

		for (int pageIndex = 0; pageIndex < document.getNumberOfPages(); pageIndex++) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			BufferedImage bim = pdfRenderer.renderImage(pageIndex);
			ImageIO.write(bim, "png", baos);
			ByteArrayInputStream byteInputStream=new ByteArrayInputStream(baos.toByteArray());
			BladeFile bladeFile = ossBuilder.template().putFile(System.currentTimeMillis()+"-pdf转换",byteInputStream);
			resultList.add(bladeFile.getLink());
//			resultList.add(baos.toByteArray());
		}

		document.close();
//		return baos.toByteArray();
		bladeRedis.set(RedisKeyConstant.PDF_CONVERT_IMG+pdfUrl,resultList);
		return R.data(resultList);
	}


	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入materialLibrary")
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	public R<MaterialLibraryVO> detail(MaterialLibraryEntity entity) {
		MaterialLibraryEntity detail = materialLibraryService.getOne(Condition.getQueryWrapper(entity));
		return R.data(MaterialLibraryWrapper.build().entityVO(detail));
	}

	/**
	 * 素材库 自定义分页
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "分页、详情", notes = "传入materialLibrary")
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	public R<IPage<MaterialLibraryVO>> page(MaterialLibraryVO materialLibrary, Query query) {
		/**
		 * 前台搜索有传保密等级
		 */
		if (null!=materialLibrary.getSecrecyLevel()) materialLibrary.setSecrecyLevelSearch(materialLibrary.getSecrecyLevel());
		/**
		 * 添加保密等级
		 */
		materialLibrary.setSecrecyLevel(commonUtil.getUserBaseEntity().getSecrecyLevel());
		materialLibrary.setStatus(2);//表示已保存的资源
		IPage<MaterialLibraryVO> pages = materialLibraryService.selectMaterialLibraryPage(Condition.getPage(query), materialLibrary,0);
		return R.data(pages);
	}



	/**
	 * 课程库 自定义分页
	 */
	@GetMapping("/list-course")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "课程库、详情", notes = "传入materialLibrary")
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	public R coursePage(MaterialLibraryVO materialLibrary, Query query) {
		/**
		 * 前台搜索有传保密等级
		 */
		if (null!=materialLibrary.getSecrecyLevel()) materialLibrary.setSecrecyLevelSearch(materialLibrary.getSecrecyLevel());
		/**
		 * 添加保密等级
		 */
		materialLibrary.setSecrecyLevel(commonUtil.getUserBaseEntity().getSecrecyLevel());
		materialLibrary.setStatus(2);//表示已保存的资源
		IPage<MaterialLibraryVO> pages = materialLibraryService.selectMaterialLibraryPage(Condition.getPage(query), materialLibrary,1);
		return R.data(pages);
	}

	@GetMapping("/list-item")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "教具库、详情", notes = "传入materialLibrary")
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	public R itemPage(MaterialLibraryVO materialLibrary, Query query) {
		/**
		 * 前台搜索有传保密等级
		 */
		if (null!=materialLibrary.getSecrecyLevel()) materialLibrary.setSecrecyLevelSearch(materialLibrary.getSecrecyLevel());
		/**
		 * 添加保密等级
		 */
		materialLibrary.setSecrecyLevel(commonUtil.getUserBaseEntity().getSecrecyLevel());
		materialLibrary.setStatus(2);//表示已保存的资源
		IPage<MaterialLibraryVO> pages = materialLibraryService.selectMaterialLibraryPage(Condition.getPage(query), materialLibrary,2);
		return R.data(pages);
	}


	/**
	 * 素材库 修改
	 */
	@PostMapping("/update")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "修改", notes = "传入materialLibrary")
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	public R update(@Valid @RequestBody MaterialLibraryEntity materialLibrary) {
		/**
		 * 判断该资源是否是此用户创建 、或者此用户是否为超级管理员
		 */
		resourceValid(materialLibrary.getId());
		return R.status(materialLibraryService.updateById(materialLibrary));
	}

	/**
	 * 素材库 删除
	 */
	@PostMapping("/remove")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "逻辑删除", notes = "传入ids")
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		List<Long> list= Func.toLongList(ids);
		list.forEach(this::resourceValid);

		return R.status(materialLibraryService.deleteLogic(list));
	}


	/**
	 * 上传资源文件并保存至附件表
	 * status修改为2
	 * @return ObjectStat
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@ServiceLog(value = TrainingOperateConstant.LIBRARY, operate = TrainingOperateConstant.ADD, describe = "新增业务资源")
	@SneakyThrows
	@ApiOperationSupport(order = 8)
	@PostMapping("/save-file")
	@ApiOperation(value = "保存资源文件", notes = "传入文件,文件名按需传入")
	public R putFileAttachVedio(LibraryBo bo) {
		MaterialLibraryEntity entity = materialLibraryService.getOne(Wrappers.<MaterialLibraryEntity>query().lambda().in(MaterialLibraryEntity::getStoragePath, bo.getFile()));
		entity.setCategory(bo.getCategory());
		entity.setSecrecyLevel(bo.getSecrecyLevel());
		entity.setIsPrivateDocument(bo.getIsPrivateDocument());
		entity.setMeterialName(bo.getMeterialName());
		entity.setStatus(2);//表示已保存
		return R.status(materialLibraryService.updateById(entity));
	}


	/**
	 * 上传资源文件并保存至附件表
	 * 此时status默认为1
	 * @return ObjectStat
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@ServiceLog(value = TrainingOperateConstant.LIBRARY, operate = TrainingOperateConstant.UPLOAD, describe = "上传文件资源")
	@SneakyThrows
	@ApiOperationSupport(order = 9)
	@PostMapping("/upload-file")
	@ApiOperation(value = "上传文件资源", notes = "上传文件资源")
	public R<String> putFile(MultipartFile file) {
		String fileName = file.getOriginalFilename();
		BladeFile bladeFile = ossBuilder.template().putFile(fileName, file.getInputStream());
		MaterialLibraryEntity entity = buildAttach(fileName, file.getSize(), bladeFile,
			AttachType.DEFAULT.getCategory(),SecrecyLevel.NORMAL.getCode(),0);
		return R.data(entity.getStoragePath());
	}

	@ServiceLog(value = TrainingOperateConstant.LIBRARY, operate = TrainingOperateConstant.UPLOAD, describe = "上传文件资源")
	@SneakyThrows
	@ApiOperationSupport(order = 9)
	@PostMapping("/upload-file-training")
	@ApiOperation(value = "上传文件资源,返回名称和链接", notes = "上传文件资源")
	public R putFileTraining(MultipartFile file) {
		String fileName = file.getOriginalFilename();
		BladeFile bladeFile = ossBuilder.template().putFile(fileName, file.getInputStream());
		MaterialLibraryEntity entity = buildAttach(fileName, file.getSize(), bladeFile,
			AttachType.DEFAULT.getCategory(),SecrecyLevel.NORMAL.getCode(),0);
		Map<String,String> map=new HashMap<>();
		map.put("link",entity.getStoragePath());
		if (StringUtils.isNotBlank(fileName))map.put("meterialName",fileName.substring(0,fileName.lastIndexOf(".")));

		return R.data(map);
	}

	/**
	 * 试题富文本图片上传并保存至附件表
	 * 此时status默认为1
	 * @return ObjectStat
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@ServiceLog(value = TrainingOperateConstant.LIBRARY, operate = TrainingOperateConstant.UPLOAD, describe = "试题图片上传并保存至附件表")
	@SneakyThrows
	@ApiOperationSupport(order = 10)
	@PostMapping("/question-upload-file")
	@ApiOperation(value = "试题图片上传", notes = "试题图片上传")
	public R<String> questionPutFile(MultipartFile file) {
		String fileName =file.getOriginalFilename();
		BladeFile bladeFile = ossBuilder.template().putFile(fileName, file.getInputStream());
		MaterialLibraryEntity entity = buildAttach(fileName, file.getSize(), bladeFile,AttachType.QUESTION_IMG.getCategory(),SecrecyLevel.NORMAL.getCode(),0);
		return R.data(entity.getStoragePath());
	}


	/**
	 * 构建附件表
	 * @param fileName  文件名
	 * @param fileSize  文件大小
	 * @param bladeFile 对象存储文件
	 * @param category  文件所属业务类型
	 * @return attachId
	 */
	private MaterialLibraryEntity buildAttach(String fileName, Long fileSize, BladeFile bladeFile, Integer category, Integer secrecyLevel, Integer isPrivateDocument) {
		String fileExtension = FileUtil.getFileExtension(fileName);
		MaterialLibraryEntity entity = new MaterialLibraryEntity();
		String linkUrl=bladeFile.getLink();
//		String replaceUrl="http://"+serviceIp.getServiceIp()+":9000/000000-training";
//		String link = linkUrl.replace(bladeFile.getDomain(), replaceUrl);

		entity.setStoragePath(linkUrl);
		entity.setDomainUrl(bladeFile.getDomain());
		entity.setMeterialName(bladeFile.getOriginalName());
		entity.setMeterialSize(fileSize);
		entity.setExtension(fileExtension);
		entity.setCategory(category);
		entity.setSecrecyLevel(secrecyLevel);
		entity.setIsPrivateDocument(isPrivateDocument);
		materialLibraryService.save(entity);
		return entity;
	}

	/**
	 * 判断该资源是否是此用户创建 、或者此用户是否为超级管理员
	 */
	private void resourceValid(Long materialId){
		if (!commonUtil.checkRoleAlias(TrainingRoleConstant.Administrator)){
			MaterialLibraryEntity entity = materialLibraryService.getById(materialId);
			if (!entity.getCreateUser().equals(AuthUtil.getUserId())) {
				throw new ServiceException("您不是此资源的拥有者,无法进行此操作!");
			}
		}

	}

}
